home *** CD-ROM | disk | FTP | other *** search
/ Complete Linux / Complete Linux.iso / docs / apps / database / postgres / postgre4.z / postgre4 / src / utils / error / trace.c < prev   
Encoding:
C/C++ Source or Header  |  1992-08-27  |  11.8 KB  |  585 lines

  1.  
  2. /*
  3.  *  TRACE.C
  4.  *
  5.  *    System tracing routines
  6.  */
  7.  
  8. #include <stdio.h>    /* XXX use own I/O routines */
  9. #include <sys/file.h>    /* XXX use own I/O routines */
  10.  
  11. #include "tmp/c.h"
  12.  
  13. RcsId("$Header: /private/postgres/src/utils/error/RCS/trace.c,v 1.15 1991/11/11 19:31:43 mer Exp $");
  14.  
  15. #include "tmp/simplelists.h"
  16. #include "utils/module.h"
  17. #include "utils/log.h"
  18. #include "utils/mcxt.h"
  19.  
  20. #ifdef sprite
  21. #include "sprite_file.h"
  22. #include "sprite_file2.h"
  23. #else
  24. #include "storage/fd.h"
  25. #endif /* sprite */
  26.  
  27. typedef struct {
  28.     char *Child;
  29.     char *Parent1;
  30.     char *Parent2;
  31. } TraceHier;
  32.  
  33. /*
  34.  *  This array defines the parent heirarchy.  Individual modules can 
  35.  *  declare local trace variables with 'parents' such that turning the
  36.  *  trace on for the parent will turn the trace on for all its children.
  37.  *
  38.  *    CHILD        PARENT#1    PARENT#2
  39.  */
  40.  
  41. static TraceHier TraceTree[] = {
  42.     "Root",        NULL,    NULL,
  43.     "Memory",   "Root",    NULL,
  44.     "Parser",   "Root",    NULL,
  45.     "Planner",  "Root",    NULL,
  46.     "Tcop",        "Root",    NULL,
  47.     "Rules",    "Root",    NULL,
  48.     "Storage",  "Root",    NULL,
  49.     "Executor", "Root",    NULL
  50. };
  51.  
  52.  
  53.  
  54. extern String getenv();    /* XXX style: use include */
  55.  
  56. static GlobalMemory TraceCxt;   /* used for memory allocation        */
  57. static int     TSDepth;        /* how deep are we?            */
  58. static SLList  TBList;        /* list of known module trace blocks    */
  59. static SLList  TSList;        /* subroutine stack trace        */
  60. static FileNumber    TraceFile;    /* current trace file (fdcache)        */
  61. static char    *DefaultTraceFile = "/dev/null";
  62.  
  63. extern char    **environ;
  64.  
  65. /*
  66.  * TraceInitialize --
  67.  */
  68.  
  69. void TraceInitialize ARGS((TraceBlock *));
  70. void WriteSpaces ARGS((File, int, int));
  71. char *TailName    ARGS((char *));
  72. Pointer TraceAlloc ARGS((int));
  73. void TraceFree ARGS((Pointer, int));
  74.  
  75. /*
  76.  *  Resource control
  77.  */
  78.  
  79. static int NumEnabled;    /* have we been initialized? .. count # of times */
  80.  
  81. void
  82. EnableTrace(enable)
  83. {
  84.     static int fail;
  85.  
  86.     Assert(fail == 0);
  87.  
  88.     if (!enable && --NumEnabled) 
  89.     return;
  90.     if (enable && NumEnabled++)
  91.     return;
  92.  
  93.     ++fail;
  94.     if (enable) {
  95.     EnableFDCache(true);
  96.     EnableMemoryContext(true);
  97.  
  98.         SLNewList(&TBList, offsetof(TraceBlock,Node));
  99.         SLNewList(&TSList, offsetof(TraceStack,Node));
  100.     TraceCxt = CreateGlobalMemory("Trace");
  101.     InitializeTheGlobalArray();
  102.     if (getenv("TRACEFILE"))
  103.         DefaultTraceFile = getenv("TRACEFILE");
  104.     TraceFile = 
  105.         FileNameOpenFile(DefaultTraceFile,O_WRONLY|O_APPEND|O_CREAT,0666);
  106.     Assert(TraceFile >= 0);
  107.         {
  108.         register char *ptr;
  109.         register short i, j;
  110.         char tracename[128];
  111.  
  112.         for (i = 0; ptr = environ[i]; ++i) {
  113.         uint32 traceLevel;
  114.             if (strncmp(ptr, "TRACE_", 6) != 0)
  115.             continue;
  116.         strcpy(tracename, ptr + 6);
  117.         for (j = 0; tracename[j] && tracename[j] != '='; ++j);
  118.         tracename[j] = 0;
  119.         traceLevel = atoi(tracename + j + 1);
  120.         if (traceLevel == 0)
  121.             traceLevel = 1;
  122.         SetTraceLevel(tracename, traceLevel);
  123.         }
  124.     }
  125.     } else {
  126.     {
  127.         register TraceBlock *tb;
  128.  
  129.         while (tb = (TraceBlock *)SLRemHead(&TBList)) {
  130.         tb->Flags = 0;
  131.         tb->Level = 0;
  132.         }
  133.     }
  134.     DefaultTraceFile = "/dev/tty";
  135.     GlobalMemoryDestroy(TraceCxt);
  136.     EnableFDCache(false);
  137.     EnableMemoryContext(false);
  138.     }
  139.     --fail;
  140. }
  141.  
  142. _TraceMsg(tb, level, nargs, arg0)
  143. TraceBlock *tb;
  144. int level, nargs;
  145. Pointer arg0;
  146. {
  147.     Assert(NumEnabled);
  148.     if ((tb->Flags & TBF_INITIALIZED) == 0)
  149.     TraceInitialize(tb);
  150.     if (level <= tb->Level) {
  151.         Pointer *args = &arg0;
  152.     char buf[1024];
  153.     int len;
  154.  
  155.     sprintf(buf, args[0], args[1], args[2], args[3], args[4], args[5]);
  156.     len = strlen(buf);
  157.     Assert(len < sizeof(buf));
  158.     buf[len++] = '\n';
  159.     switch(tb->Stream) {
  160.     case DefaultStream:
  161.     case LogStream:
  162.     case InstallationStream:
  163.     case DBStream:
  164.     case ConsoleStream:
  165.     case FrontendStream:
  166.     case PostmasterStream:
  167.     case AuxStream:
  168.         FileWrite(TraceFile, buf, len);
  169.         break;
  170.     default:
  171.         elog(WARN, "Unknown trace stream %s %d", tb->Name, tb->Stream);
  172.         break;
  173.     }
  174.     } 
  175. }
  176.  
  177. /*
  178.  *   If not already initialized, initialize a trace block.
  179.  */
  180.  
  181. void
  182. TraceInitialize(tb)
  183. TraceBlock *tb;
  184. {
  185.     if (tb->Flags & TBF_INITIALIZED)
  186.     return;
  187.  
  188.     Assert(NumEnabled);
  189.  
  190.     /*
  191.      *  Remove header and tailer spaces from Parent1 and Parent2 that might
  192.      *  have been stuck in by cpp.
  193.      */
  194.  
  195.     RemoveHeadTailSpaces(&tb->Parent1);
  196.     RemoveHeadTailSpaces(&tb->Parent2);
  197.  
  198.     /*
  199.      *  Initial trace level determined by max of any parent's trace level.
  200.      */
  201.  
  202.     {
  203.     uint32 l1 = TraceLevelByName(tb->Parent1);
  204.     uint32 l2 = TraceLevelByName(tb->Parent2);
  205.  
  206.     tb->Level = Max(l1,l2);
  207.     }
  208.  
  209.     /*
  210.      *  Trace level overriden by specific level already set for this name
  211.      *  (level for all matched names are the same)
  212.      */
  213.  
  214.     {
  215.     register TraceBlock *t, *tnext;
  216.     for (t = (TraceBlock *)SLGetHead(&TBList); t; t = tnext) {
  217.         tnext = (TraceBlock *)SLGetSucc(&t->Node);
  218.         if (strcmp(tb->Name, t->Name) == 0) {
  219.         tb->Level = t->Level;
  220.         break;
  221.         }
  222.     }
  223.     }
  224.  
  225.     /*
  226.      *  Add trace block to TB list.
  227.      */
  228.  
  229.     SLNewNode(&tb->Node);
  230.     SLAddTail(&TBList, &tb->Node);
  231.     tb->Flags |= TBF_INITIALIZED;
  232. }
  233.  
  234. RemoveHeadTailSpaces(str)
  235. char **str;
  236. {
  237.     register char *ptr = *str;
  238.  
  239.     if (ptr) {
  240.     while (*ptr == ' ' || *ptr == '\t')
  241.         ++ptr;
  242.     *str = ptr;
  243.     while (*ptr && *ptr != ' ' && *ptr != '\t')
  244.         ++ptr;
  245.     *ptr = 0;
  246.     }
  247. }
  248.  
  249. InitializeTheGlobalArray()
  250. {
  251.     register short i;
  252.  
  253.     for (i = 0; i < lengthof(TraceTree); ++i) {
  254.     register TraceBlock *tb = (TraceBlock *)TraceAlloc(sizeof(TraceBlock));
  255.     bzero(tb, sizeof(TraceBlock));
  256.     tb->Name    = TraceTree[i].Child;
  257.     tb->Parent1 = TraceTree[i].Parent1;
  258.     tb->Parent2 = TraceTree[i].Parent2;
  259.     tb->Flags = TBF_INITIALIZED;
  260.     SLNewNode(&tb->Node);
  261.     SLAddTail(&TBList, &tb->Node);
  262.     }
  263. }
  264.  
  265. /*
  266.  *   TraceLevelByName()
  267.  *
  268.  *   Return the trace level associated with the given trace variable
  269.  *   name.  (0 if not found)
  270.  */
  271.  
  272. static
  273. int
  274. TraceLevelByName(name)
  275. char *name;
  276. {
  277.     register TraceBlock *tb;
  278.  
  279.     Assert(NumEnabled);
  280.     if (name == NULL)
  281.     return(0);
  282.     for (tb = (TraceBlock *)SLGetHead(&TBList); tb;
  283.      tb = (TraceBlock *)SLGetSucc(&tb->Node))
  284.     {
  285.     if (strcmp(tb->Name, name) == 0)
  286.         return(tb->Level);
  287.     }
  288.     return(0);
  289. }
  290.  
  291. /*
  292.  *    SetChildrenOf()
  293.  *
  294.  *    Subroutine used by SetTraceLevel() to search out the children of
  295.  *    a name and modify their level recursively.
  296.  */
  297.  
  298. static void
  299. SetChildrenOf(Name, level)
  300. char *Name;
  301. {
  302.     register TraceBlock *tb;
  303.  
  304.     Assert(NumEnabled);
  305.  
  306.     for (tb = (TraceBlock *)SLGetHead(&TBList); tb;
  307.         tb = (TraceBlock *)SLGetSucc(&tb->Node))
  308.     {
  309.     if (tb->Parent1 && strcmp(tb->Parent1, Name) == 0) {
  310.         if (tb->Flags & TBF_FAULT)    /* circular tree! */
  311.         Assert(0);
  312.         tb->Level = level;
  313.         tb->Flags |= TBF_FAULT;
  314.         SetChildrenOf(tb->Name, level);
  315.         tb->Flags &= ~TBF_FAULT;
  316.     }
  317.     if (tb->Parent2 && strcmp(tb->Parent2, Name) == 0) {
  318.         if (tb->Flags & TBF_FAULT)  /* circular tree! */
  319.         Assert(0);
  320.         tb->Level = level;
  321.         tb->Flags |= TBF_FAULT;
  322.         SetChildrenOf(tb->Name, level);
  323.         tb->Flags &= ~TBF_FAULT;
  324.     }
  325.     }
  326. }
  327.  
  328. /*
  329.  *    SetTraceLevel()
  330.  *
  331.  *    Modify the current trace level for the given trace variable.  0 turns
  332.  *    off the trace.  The level for all children is recursively set to
  333.  *    this value too.
  334.  *
  335.  *    Note that more than one traceblock with the same name may exist.
  336.  */
  337.  
  338. void
  339. SetTraceLevel(traceName, level)
  340. char *traceName;
  341. int level;
  342. {
  343.     short found = 0;
  344.  
  345.  
  346.     Assert(NumEnabled);
  347.  
  348.     /*
  349.      *  Step (1), search list and update any matches.
  350.      */
  351.  
  352.     {
  353.     register TraceBlock *tb;
  354.  
  355.     for (tb = (TraceBlock *)SLGetHead(&TBList); tb;
  356.          tb = (TraceBlock *)SLGetSucc(&tb->Node))
  357.     {
  358.         if (strcmp(traceName, tb->Name) == 0) {
  359.         tb->Level = level;
  360.         found = 1;
  361.         }
  362.     }
  363.     }
  364.  
  365.     /*
  366.      *  Step (2), update children of this trace name, if any (recur)
  367.      */
  368.  
  369.     SetChildrenOf(traceName, level);
  370.  
  371.     /*
  372.      *  Step (3), if name was not in block list, add to block list.
  373.      */
  374.  
  375.     if (found == 0) {
  376.     register TraceBlock *tb = (TraceBlock *)TraceAlloc(sizeof(*tb));
  377.     char *ptr = TraceAlloc(strlen(traceName)+1);
  378.  
  379.     SLNewNode(&tb->Node);
  380.     strcpy(ptr, traceName);
  381.     tb->Name = ptr;
  382.     tb->Flags = TBF_INITIALIZED;
  383.     tb->Level = level;
  384.     SLAddHead(&TBList, &tb->Node);
  385.     }
  386. }
  387.  
  388. /*
  389.  *  Change the TraceFile messages are sent to.  On failure, the old trace
  390.  *  file continues to be used.
  391.  */
  392.  
  393. bool
  394. TraceFileName(fileName)
  395. char *fileName;
  396. {
  397.     FileNumber newfile;
  398.     char buf[256];
  399.  
  400.     newfile = FileNameOpenFile(fileName,O_WRONLY|O_APPEND|O_CREAT,0666);
  401.     if (newfile < 0) {
  402.     sprintf(buf, "Unable to open new trace file %s\n", fileName);
  403.     FileWrite(TraceFile, buf, strlen(buf));
  404.     return(false);
  405.     }
  406.     FileClose(TraceFile);
  407.     TraceFile = newfile;
  408.     return(true);
  409. }
  410.  
  411. /*
  412.  *  Subroutine Call/Return tracing
  413.  */
  414.  
  415. void
  416. _TracePush(tb, lineno, str)
  417. TraceBlock *tb;
  418. int lineno;
  419. char *str;
  420. {
  421.     register TraceStack *ts;
  422.  
  423.     Assert(NumEnabled);
  424.     if ((tb->Flags & TBF_INITIALIZED) == 0)
  425.     TraceInitialize(tb);
  426.  
  427.     ts = (TraceStack *)TraceAlloc(sizeof(*ts));
  428.     ts->Tb = tb;
  429.     ts->LineNo = lineno;
  430.     ts->Text   = str;
  431.     SLNewNode(&ts->Node);
  432.     SLAddTail(&TSList, &ts->Node);
  433.     ++TSDepth;
  434.  
  435.     if (tb->Level) {
  436.     char buf[256];
  437.     WriteSpaces(TraceFile, TSDepth, '#');
  438.     sprintf(buf, "BEGIN %s.%d %s\n", TailName(tb->Module), lineno, str);
  439.     FileWrite(TraceFile, buf, strlen(buf));
  440.     }
  441. }
  442.  
  443. void
  444. _TracePop(tb, lineno, str)
  445. TraceBlock *tb;
  446. int lineno;
  447. char *str;
  448. {
  449.     register TraceStack *ts = (TraceStack *)SLGetTail(&TSList);
  450.  
  451.     Assert(PointerIsValid(ts));
  452.     Assert(ts->Tb == tb);
  453.     SLRemove(&ts->Node);
  454.     TraceFree((Pointer)ts, sizeof(*ts));
  455.  
  456.     if (str[0] == '\0')
  457.     str = ts->Text;
  458.  
  459.     if (tb->Level) {
  460.     char buf[256];
  461.     WriteSpaces(TraceFile, TSDepth, '#');
  462.     sprintf(buf, "END   %s.%d %s\n", TailName(tb->Module), lineno, str);
  463.     FileWrite(TraceFile, buf, strlen(buf));
  464.     }
  465.     --TSDepth;
  466. }
  467.  
  468. void
  469. _TraceReset(tb, lineno, str)
  470. TraceBlock *tb;
  471. int lineno;
  472. char *str;
  473. {
  474.  
  475. }
  476.  
  477. /*
  478.  *  Called by exception handler
  479.  */
  480.  
  481. void
  482. _TraceDump()
  483. {
  484.     TraceStack *ts;
  485.     char buf[256];
  486.     static int ReEntered = 0;
  487.  
  488.     if (NumEnabled <= 0)
  489.     return;
  490.     if (ReEntered)
  491.     exitpg(1234); 
  492.     ++ReEntered;
  493.  
  494.     sprintf(buf, "\nTRACE STACK DUMP\n");
  495.     FileWrite(TraceFile, buf, strlen(buf));
  496.  
  497.     for (ts = (TraceStack *)SLGetHead(&TSList);
  498.      PointerIsValid(ts);
  499.      ts = (TraceStack *)SLGetSucc(&ts->Node))
  500.     {
  501.     sprintf(buf, "%15s.%-4d\t%s\n", ts->Tb->Module, ts->LineNo, ts->Text);
  502.     FileWrite(TraceFile, buf, strlen(buf));
  503.     }
  504.     sprintf(buf, "\nTRACE STACK END\n");
  505.     FileWrite(TraceFile, buf, strlen(buf));
  506.     --ReEntered;
  507. }
  508.  
  509. static void
  510. WriteSpaces(file, n, firstchar)
  511. FileNumber file;
  512. int n;
  513. int firstchar;
  514. {
  515.     char buf[256];
  516.     int i;
  517.  
  518.     ++n;
  519.     for (i = 0; i < n && i < sizeof(buf); ++i)
  520.     buf[i] = ' ';
  521.     buf[0] = '#';
  522.     while (n > sizeof(buf)) {
  523.     FileWrite(file, buf, n);
  524.     buf[0] = ' ';
  525.     n -= sizeof(buf);
  526.     }
  527.     FileWrite(file, buf, n);
  528. }
  529.  
  530. char *
  531. TailName(str)
  532. char *str;
  533. {
  534.     char *ptr = str + strlen(str);
  535.     while (ptr >= str && *ptr != '/')
  536.     --ptr;
  537.     return(ptr + 1);
  538. }
  539.  
  540. /*
  541.  *  ALLOCATION AND FREEING OF MEMORY
  542.  *
  543.  *  Allocations smaller than 32 longwords are tabled for fast access.
  544.  *  (that is, TraceFree() calls table the pointer instead of freeing it)
  545.  */
  546.  
  547. static char **AllocArray[32];
  548.  
  549. Pointer
  550. TraceAlloc(bytes)
  551. {
  552.     int longwords;
  553.     char **res;
  554.  
  555.     if (bytes < sizeof(char *))
  556.     bytes = sizeof(char *);
  557.     longwords = (bytes + 3) >> 2;    /* # of longwords to allocate */
  558.     if (longwords >= lengthof(AllocArray) || AllocArray[longwords] == NULL) {
  559.     return(MemoryContextAlloc((MemoryContext)TraceCxt, longwords << 2));
  560.     }
  561.     res = AllocArray[longwords];
  562.     AllocArray[longwords] = (char **)res[0];
  563.     return((Pointer)res);
  564. }
  565.  
  566. void
  567. TraceFree(ptr, bytes)
  568. Pointer ptr;
  569. int bytes;
  570. {
  571.     int longwords;
  572.     if (bytes < sizeof(char *))
  573.     bytes = sizeof(char *);
  574.     longwords = (bytes + 3) >> 2;    /* # of longwords to free */
  575.  
  576.     if (longwords >= lengthof(AllocArray)) {
  577.     MemoryContextFree((MemoryContext)TraceCxt, ptr);
  578.     return;
  579.     }
  580.     *(char **)ptr = (char *)AllocArray[longwords];
  581.     AllocArray[longwords] = (char **)ptr;
  582. }
  583.  
  584.  
  585.